<!DOCTYPE html>
<html lang="en">
    <!-- title -->




<!-- keywords -->




<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" >
    <meta name="author" content="驿路星辰">
    <meta name="renderer" content="webkit">
    <meta name="copyright" content="驿路星辰">
    
    <meta name="keywords" content="算法,Swift,Dart,iOS,Flutter,C++">
    
    <meta name="description" content="">
    <meta name="description" content="翻译：https:&#x2F;&#x2F;www.raywenderlich.com&#x2F;9222-an-introduction-to-functional-programming-in-swift#toc-anchor-012 在本教程中，您将逐步学习如何开始使用函数式编程以及如何编写声明性代码而不是命令式代码。 swift于2014年在WWDC上进入编程世界的大门，它不仅仅是一门新的编程语言。 它为iOS和macO">
<meta property="og:type" content="article">
<meta property="og:title" content="【译】如何在swift中使用函数式编程">
<meta property="og:url" content="http://kurumi.gitee.io/shanks/2019/10/03/how-to-use-functional-program-in-swift/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="翻译：https:&#x2F;&#x2F;www.raywenderlich.com&#x2F;9222-an-introduction-to-functional-programming-in-swift#toc-anchor-012 在本教程中，您将逐步学习如何开始使用函数式编程以及如何编写声明性代码而不是命令式代码。 swift于2014年在WWDC上进入编程世界的大门，它不仅仅是一门新的编程语言。 它为iOS和macO">
<meta property="og:locale" content="en_US">
<meta property="og:image" content="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/10/3/16d9244e23c78c87~tplv-t2oaga2asx-image.image">
<meta property="og:image" content="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/10/3/16d924565d497ebb~tplv-t2oaga2asx-image.image">
<meta property="article:published_time" content="2019-10-03T13:50:34.000Z">
<meta property="article:modified_time" content="2022-05-02T05:51:49.849Z">
<meta property="article:author" content="驿路星辰">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/10/3/16d9244e23c78c87~tplv-t2oaga2asx-image.image">
    <meta http-equiv="Cache-control" content="no-cache">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    
    <title>【译】如何在swift中使用函数式编程 · iOS</title>
    <style type="text/css">
    @font-face {
        font-family: 'Oswald-Regular';
        src: url("/shanks/font/Oswald-Regular.ttf");
    }

    body {
        margin: 0;
    }

    header,
    footer,
    .back-top,
    .sidebar,
    .container,
    .site-intro-meta,
    .toc-wrapper {
        display: none;
    }

    .site-intro {
        position: relative;
        z-index: 3;
        width: 100%;
        /* height: 30vh; */
        overflow: hidden;
    }

    .site-intro-placeholder {
        position: absolute;
        z-index: -2;
        top: 0;
        left: 0;
        width: calc(100% + 300px);
        height: 100%;
        background: repeating-linear-gradient(-45deg, #444 0, #444 80px, #333 80px, #333 160px);
        background-position: center center;
        transform: translate3d(-226px, 0, 0);
        animation: gradient-move 2.5s ease-out 0s infinite;
    }

    @keyframes gradient-move {
        0% {
            transform: translate3d(-226px, 0, 0);
        }
        100% {
            transform: translate3d(0, 0, 0);
        }
    }

</style>

    <link rel="preload" href= "/shanks/css/style.css?v=20180824" as="style" onload="this.onload=null;this.rel='stylesheet'" />
    <link rel="stylesheet" href= "/shanks/css/mobile.css?v=20180824" media="(max-width: 980px)">
    
    <link rel="preload" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.2.5/jquery.fancybox.min.css" as="style" onload="this.onload=null;this.rel='stylesheet'" />
    
    <!-- /*! loadCSS. [c]2017 Filament Group, Inc. MIT License */
/* This file is meant as a standalone workflow for
- testing support for link[rel=preload]
- enabling async CSS loading in browsers that do not support rel=preload
- applying rel preload css once loaded, whether supported or not.
*/ -->
<script>
(function( w ){
	"use strict";
	// rel=preload support test
	if( !w.loadCSS ){
		w.loadCSS = function(){};
	}
	// define on the loadCSS obj
	var rp = loadCSS.relpreload = {};
	// rel=preload feature support test
	// runs once and returns a function for compat purposes
	rp.support = (function(){
		var ret;
		try {
			ret = w.document.createElement( "link" ).relList.supports( "preload" );
		} catch (e) {
			ret = false;
		}
		return function(){
			return ret;
		};
	})();

	// if preload isn't supported, get an asynchronous load by using a non-matching media attribute
	// then change that media back to its intended value on load
	rp.bindMediaToggle = function( link ){
		// remember existing media attr for ultimate state, or default to 'all'
		var finalMedia = link.media || "all";

		function enableStylesheet(){
			link.media = finalMedia;
		}

		// bind load handlers to enable media
		if( link.addEventListener ){
			link.addEventListener( "load", enableStylesheet );
		} else if( link.attachEvent ){
			link.attachEvent( "onload", enableStylesheet );
		}

		// Set rel and non-applicable media type to start an async request
		// note: timeout allows this to happen async to let rendering continue in IE
		setTimeout(function(){
			link.rel = "stylesheet";
			link.media = "only x";
		});
		// also enable media after 3 seconds,
		// which will catch very old browsers (android 2.x, old firefox) that don't support onload on link
		setTimeout( enableStylesheet, 3000 );
	};

	// loop through link elements in DOM
	rp.poly = function(){
		// double check this to prevent external calls from running
		if( rp.support() ){
			return;
		}
		var links = w.document.getElementsByTagName( "link" );
		for( var i = 0; i < links.length; i++ ){
			var link = links[ i ];
			// qualify links to those with rel=preload and as=style attrs
			if( link.rel === "preload" && link.getAttribute( "as" ) === "style" && !link.getAttribute( "data-loadcss" ) ){
				// prevent rerunning on link
				link.setAttribute( "data-loadcss", true );
				// bind listeners to toggle media back
				rp.bindMediaToggle( link );
			}
		}
	};

	// if unsupported, run the polyfill
	if( !rp.support() ){
		// run once at least
		rp.poly();

		// rerun poly on an interval until onload
		var run = w.setInterval( rp.poly, 500 );
		if( w.addEventListener ){
			w.addEventListener( "load", function(){
				rp.poly();
				w.clearInterval( run );
			} );
		} else if( w.attachEvent ){
			w.attachEvent( "onload", function(){
				rp.poly();
				w.clearInterval( run );
			} );
		}
	}


	// commonjs
	if( typeof exports !== "undefined" ){
		exports.loadCSS = loadCSS;
	}
	else {
		w.loadCSS = loadCSS;
	}
}( typeof global !== "undefined" ? global : this ) );
</script>

    <link rel="icon" href= "/shanks/assets/favicon.ico" />
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.min.js" as="script" />
    <link rel="preload" href="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js" as="script" />
    <link rel="preload" href="/shanks/scripts/main.js" as="script" />
    <link rel="preload" as="font" href="/shanks/font/Oswald-Regular.ttf" crossorigin>
    <link rel="preload" as="font" href="https://at.alicdn.com/t/font_327081_1dta1rlogw17zaor.woff" crossorigin>
    
    <!-- fancybox -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fancybox/3.2.5/jquery.fancybox.min.js" defer></script>
    <!-- 百度统计  -->
    
    <!-- 谷歌统计  -->
    
<meta name="generator" content="Hexo 4.2.1"></head>

    
        <body class="post-body">
    
    
<header class="header">

    <div class="read-progress"></div>
    <div class="header-sidebar-menu">&#xe775;</div>
    <!-- post页的toggle banner  -->
    
    <div class="banner">
            <div class="blog-title">
                <a href="/shanks/" >驿路星辰的博客</a>
            </div>
            <div class="post-title">
                <a href="#" class="post-name">【译】如何在swift中使用函数式编程</a>
            </div>
    </div>
    
    <a class="home-link" href=/shanks/>驿路星辰的博客</a>
</header>
    <div class="wrapper">
        <div class="site-intro" style="







height:50vh;
">
    
    <!-- 主页  -->
    
    
    <!-- 404页  -->
            
    <div class="site-intro-placeholder"></div>
    <div class="site-intro-img" style="background-image: url(/shanks/intro/post-bg.jpg)"></div>
    <div class="site-intro-meta">
        <!-- 标题  -->
        <h1 class="intro-title">
            <!-- 主页  -->
            
            【译】如何在swift中使用函数式编程
            <!-- 404 -->
            
        </h1>
        <!-- 副标题 -->
        <p class="intro-subtitle">
            <!-- 主页副标题  -->
            
            
            <!-- 404 -->
            
        </p>
        <!-- 文章页meta -->
        
            <div class="post-intros">
                <!-- 文章页标签  -->
                
                
                    <div class="post-intro-read">
                        <span>Word count: <span class="post-count word-count">7k</span>Reading time: <span class="post-count reading-time">30 min</span></span>
                    </div>
                
                <div class="post-intro-meta">
                    <span class="post-intro-calander iconfont-archer">&#xe676;</span>
                    <span class="post-intro-time">2019/10/03</span>
                    
                    <span id="busuanzi_container_page_pv" class="busuanzi-pv">
                        <span class="iconfont-archer">&#xe602;</span>
                        <span id="busuanzi_value_page_pv"></span>
                    </span>
                    
                    <span class="shareWrapper">
                        <span class="iconfont-archer shareIcon">&#xe71d;</span>
                        <span class="shareText">Share</span>
                        <ul class="shareList">
                            <li class="iconfont-archer share-qr" data-type="qr">&#xe75b;
                                <div class="share-qrcode"></div>
                            </li>
                            <li class="iconfont-archer" data-type="weibo">&#xe619;</li>
                            <li class="iconfont-archer" data-type="qzone">&#xe62e;</li>
                            <li class="iconfont-archer" data-type="twitter">&#xe634;</li>
                            <li class="iconfont-archer" data-type="facebook">&#xe67a;</li>
                        </ul>
                    </span>
                </div>
            </div>
        
    </div>
</div>
        <script>
 
  // get user agent
  var browser = {
    versions: function () {
      var u = window.navigator.userAgent;
      return {
        userAgent: u,
        trident: u.indexOf('Trident') > -1, //IE内核
        presto: u.indexOf('Presto') > -1, //opera内核
        webKit: u.indexOf('AppleWebKit') > -1, //苹果、谷歌内核
        gecko: u.indexOf('Gecko') > -1 && u.indexOf('KHTML') == -1, //火狐内核
        mobile: !!u.match(/AppleWebKit.*Mobile.*/), //是否为移动终端
        ios: !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/), //ios终端
        android: u.indexOf('Android') > -1 || u.indexOf('Linux') > -1, //android终端或者uc浏览器
        iPhone: u.indexOf('iPhone') > -1 || u.indexOf('Mac') > -1, //是否为iPhone或者安卓QQ浏览器
        iPad: u.indexOf('iPad') > -1, //是否为iPad
        webApp: u.indexOf('Safari') == -1, //是否为web应用程序，没有头部与底部
        weixin: u.indexOf('MicroMessenger') == -1, //是否为微信浏览器
        uc: u.indexOf('UCBrowser') > -1 //是否为android下的UC浏览器
      };
    }()
  }
  console.log("userAgent:" + browser.versions.userAgent);

  // callback
  function fontLoaded() {
    console.log('font loaded');
    if (document.getElementsByClassName('site-intro-meta')) {
      document.getElementsByClassName('intro-title')[0].classList.add('intro-fade-in');
      document.getElementsByClassName('intro-subtitle')[0].classList.add('intro-fade-in');
      var postIntros = document.getElementsByClassName('post-intros')[0]
      if (postIntros) {
        postIntros.classList.add('post-fade-in');
      }
    }
  }

  // UC不支持跨域，所以直接显示
  function asyncCb(){
    if (browser.versions.uc) {
      console.log("UCBrowser");
      fontLoaded();
    } else {
      WebFont.load({
        custom: {
          families: ['Oswald-Regular']
        },
        loading: function () {  //所有字体开始加载
          // console.log('loading');
        },
        active: function () {  //所有字体已渲染
          fontLoaded();
        },
        inactive: function () { //字体预加载失败，无效字体或浏览器不支持加载
          console.log('inactive: timeout');
          fontLoaded();
        },
        timeout: 5000 // Set the timeout to two seconds
      });
    }
  }

  function asyncErr(){
    console.warn('script load from CDN failed, will load local script')
  }

  // load webfont-loader async, and add callback function
  function async(u, cb, err) {
    var d = document, t = 'script',
      o = d.createElement(t),
      s = d.getElementsByTagName(t)[0];
    o.src = u;
    if (cb) { o.addEventListener('load', function (e) { cb(null, e); }, false); }
    if (err) { o.addEventListener('error', function (e) { err(null, e); }, false); }
    s.parentNode.insertBefore(o, s);
  }

  var asyncLoadWithFallBack = function(arr, success, reject) {
      var currReject = function(){
        reject()
        arr.shift()
        if(arr.length)
          async(arr[0], success, currReject)
        }

      async(arr[0], success, currReject)
  }

  asyncLoadWithFallBack([
    "https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.min.js", 
    "https://cdn.bootcss.com/webfont/1.6.28/webfontloader.js",
    "/shanks/lib/webfontloader.min.js"
  ], asyncCb, asyncErr)
</script>        
        <img class="loading" src="/shanks/assets/loading.svg" style="display: block; margin: 6rem auto 0 auto; width: 6rem; height: 6rem;" />
        <div class="container container-unloaded">
            <main class="main post-page">
    <article class="article-entry">
        <p>翻译：<code>https://www.raywenderlich.com/9222-an-introduction-to-functional-programming-in-swift#toc-anchor-012</code></p>
<p>在本教程中，您将逐步学习如何开始使用函数式编程以及如何编写声明性代码而不是命令式代码。</p>
<p>swift于2014年在WWDC上进入编程世界的大门，它不仅仅是一门新的编程语言。 它为iOS和macOS平台的软件开发提供了便利。</p>
<p>本教程重点介绍其中一种方法：函数式编程，简称FP。 您将了解FP中使用的各种方法和技术。</p>
<h3 id="开始"><a href="#开始" class="headerlink" title="开始"></a>开始</h3><p>创建一个新的<code>playground</code>通过选择<code>File ▸ New ▸ Playground</code><br><img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/10/3/16d9244e23c78c87~tplv-t2oaga2asx-image.image" alt=""><br>设置你的<code>playground</code>，通过拖拽分割线你可以看到结果面板和控制台<br><img src="https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/10/3/16d924565d497ebb~tplv-t2oaga2asx-image.image" alt=""></p>
<p>现在删除<code>playground</code>中所有代码，添加一下行：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Foundation</span><br></pre></td></tr></table></figure>
<p>开始在大脑中回忆一些基础理论吧。</p>
<h3 id="命令式编程风格"><a href="#命令式编程风格" class="headerlink" title="命令式编程风格"></a>命令式编程风格</h3><p>当你第一次学习编码时，你可能学会了命令式的风格。 命令式风格如何运作？<br>添加下面代码到你的<code>playground</code>:</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> thing = <span class="number">3</span></span><br><span class="line"><span class="comment">//some stuff</span></span><br><span class="line">thing = <span class="number">4</span></span><br></pre></td></tr></table></figure>
<p>该代码是正常和合理的。 首先，你创建一个名为<code>thing</code>的变量等于3，然后你命令<code>thing</code>变为4。</p>
<p>简而言之,这就是命令式的风格。 您使用一些数据创建变量，然后将该变量改为其他数据。</p>
<h3 id="函数式编程概念"><a href="#函数式编程概念" class="headerlink" title="函数式编程概念"></a>函数式编程概念</h3><p>在本节中，您将了解FP中的一些关键概念。 许多论文表明<strong>immutable state(状态不变)</strong>和<strong>lack of side effects(没有副作用)</strong>是函数式编程两个最重要的特征，所以你将先学习它们。</p>
<h3 id="不变性和副作用"><a href="#不变性和副作用" class="headerlink" title="不变性和副作用"></a>不变性和副作用</h3><p>无论您首先学习哪种编程语言，您可能学到的最初概念之一是变量代表数据或状态。 如果你退一步思考这个想法，变量看起来很奇怪。</p>
<p>术语“变量”表示随程序运行而变化的数量。 从数学角度思考数量<code>thing</code>，您已经将<strong>时间</strong>作为软件运行方式的关键参数。 通过更改变量，可以创建<code>mutable state</code>(可变状态)。</p>
<p>要进行演示，请将此代码添加到您的<code>playground</code>：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">superHero</span><span class="params">()</span></span> &#123;</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"I'm batman"</span>)</span><br><span class="line">  thing = <span class="number">5</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"original state = \(thing)"</span>)</span><br><span class="line">superHero()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"mutated state = \(thing)"</span>)</span><br></pre></td></tr></table></figure>
<p>神秘变化！为什么<code>thing</code>变成5了？这种变化被称为** side effect **。函数<code>superHero（）</code>更改了一个它自己没有定义的变量。</p>
<p>单独或在简单系统中，可变状态不一定是问题。将许多对象连接在一起时会出现问题，例如在大型面向对象系统中。可变状态可能会让人很难理解变量的值以及该值随时间的变化。</p>
<p>例如，在为多线程系统编写代码时，如果两个或多个线程同时访问同一个变量，它们可能会无序地修改或访问它。这会导致意外行为。这种意外行为包括竞争条件，死锁和许多其他问题。</p>
<p>想象一下，如果你可以编写状态永远不会发生变化的代码。并发系统中出现的一大堆问题将会消失。像这样工作的系统具有不可变状态，这意味着不允许状态在程序的过程中发生变化。</p>
<p>使用不可变数据的主要好处是使用它的代码单元没有副作用。代码中的函数不会改变自身之外的元素，并且在发生函数调用时不会出现任何怪异的效果。您的程序可以预测，因为没有副作用，您可以轻松地重现其预期的效果。</p>
<p>本教程涵盖了高级的FP编程，因此在现实世界中考虑概念是有帮助的。在这种情况下，假设您正在构建一个游乐园的应用程序，并且该游乐园的后端服务器通过REST API提供数据。</p>
<h3 id="创建游乐园的模型"><a href="#创建游乐园的模型" class="headerlink" title="创建游乐园的模型"></a>创建游乐园的模型</h3><p>通过添加以下代码到<code>playground</code>去创建数据结构</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">RideCategory</span>: <span class="title">String</span>, <span class="title">CustomStringConvertible</span> </span>&#123;</span><br><span class="line">  <span class="keyword">case</span> family</span><br><span class="line">  <span class="keyword">case</span> kids</span><br><span class="line">  <span class="keyword">case</span> thrill</span><br><span class="line">  <span class="keyword">case</span> scary</span><br><span class="line">  <span class="keyword">case</span> relaxing</span><br><span class="line">  <span class="keyword">case</span> water</span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> description: <span class="type">String</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> rawValue</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">typealias</span> <span class="type">Minutes</span> = <span class="type">Double</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Ride</span>: <span class="title">CustomStringConvertible</span> </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> name: <span class="type">String</span></span><br><span class="line">  <span class="keyword">let</span> categories: <span class="type">Set</span>&lt;<span class="type">RideCategory</span>&gt;</span><br><span class="line">  <span class="keyword">let</span> waitTime: <span class="type">Minutes</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">var</span> description: <span class="type">String</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Ride –\"\(name)\", wait: \(waitTime) mins, "</span> +</span><br><span class="line">      <span class="string">"categories: \(categories)\n"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>接着通过model创建一些数据：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> parkRides = [</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Raging Rapids"</span>,</span><br><span class="line">       categories: [.family, .thrill, .water],</span><br><span class="line">       waitTime: <span class="number">45.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Crazy Funhouse"</span>, categories: [.family], waitTime: <span class="number">10.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Spinning Tea Cups"</span>, categories: [.kids], waitTime: <span class="number">15.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Spooky Hollow"</span>, categories: [.scary], waitTime: <span class="number">30.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Thunder Coaster"</span>,</span><br><span class="line">       categories: [.family, .thrill],</span><br><span class="line">       waitTime: <span class="number">60.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Grand Carousel"</span>, categories: [.family, .kids], waitTime: <span class="number">15.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Bumper Boats"</span>, categories: [.family, .water], waitTime: <span class="number">25.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Mountain Railroad"</span>,</span><br><span class="line">       categories: [.family, .relaxing],</span><br><span class="line">       waitTime: <span class="number">0.0</span>)</span><br><span class="line">]</span><br></pre></td></tr></table></figure>

<p>当你声明<code>parkRides</code>通过<code>let</code>代替<code>var</code>,数组和它的内容都不可变了。<br>尝试通过下面代码修改数组中的一个单元：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">parkRides[<span class="number">0</span>] = <span class="type">Ride</span>(name: <span class="string">"Functional Programming"</span>,</span><br><span class="line">                    categories: [.thrill], waitTime: <span class="number">5.0</span>)</span><br></pre></td></tr></table></figure>
<p>产生了一个编译错误，是个好结果。你希望Swift编译器阻止你改变数据。<br>现在删除错误的代码继续教程。</p>
<h3 id="模块化"><a href="#模块化" class="headerlink" title="模块化"></a>模块化</h3><p>使用模块化就像玩儿童积木一样。 你有一盒简单的积木，可以通过将它们连接在一起来构建一个庞大而复杂的系统。 每块砖都有一份工作，您希望您的代码具有相同的效果。</p>
<p>假设您需要一个按字母顺序排列的所有游乐设施名称列表。 从命令性地开始这样做，这意味着利用可变状态。 将以下功能添加到<code>playground</code>的底部：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sortedNamesImp</span><span class="params">(of rides: [Ride])</span></span> -&gt; [<span class="type">String</span>] &#123;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 1</span></span><br><span class="line">  <span class="keyword">var</span> sortedRides = rides</span><br><span class="line">  <span class="keyword">var</span> key: <span class="type">Ride</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">// 2</span></span><br><span class="line">  <span class="keyword">for</span> i <span class="keyword">in</span> (<span class="number">0</span>..&lt;sortedRides.<span class="built_in">count</span>) &#123;</span><br><span class="line">    key = sortedRides[i]</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 3</span></span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">stride</span>(from: i, to: -<span class="number">1</span>, by: -<span class="number">1</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> key.name.localizedCompare(sortedRides[j].name) == .orderedAscending &#123;</span><br><span class="line">        sortedRides.remove(at: j + <span class="number">1</span>)</span><br><span class="line">        sortedRides.insert(key, at: j)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="comment">// 4</span></span><br><span class="line">  <span class="keyword">var</span> sortedNames: [<span class="type">String</span>] = []</span><br><span class="line">  <span class="keyword">for</span> ride <span class="keyword">in</span> sortedRides &#123;</span><br><span class="line">    sortedNames.append(ride.name)</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> sortedNames</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedNames1 = sortedNamesImp(of: parkRides)</span><br></pre></td></tr></table></figure>
<p>你的代码完成了以下工作：</p>
<ol>
<li>创建一个变量保存排序的<code>rides</code></li>
<li>遍历传入函数的<code>rides</code></li>
<li>使用插入排序排序<code>rides</code></li>
<li>遍历排序的<code>rides</code>获得名称</li>
</ol>
<p>添加下面代码到<code>playground</code>验证函数是否按照意图执行：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedNames</span><span class="params">(<span class="number">_</span> names: [String])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Bumper Boats"</span>,</span><br><span class="line">                  <span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>,</span><br><span class="line">                  <span class="string">"Raging Rapids"</span>,</span><br><span class="line">                  <span class="string">"Spinning Tea Cups"</span>,</span><br><span class="line">                  <span class="string">"Spooky Hollow"</span>,</span><br><span class="line">                  <span class="string">"Thunder Coaster"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test sorted names = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(sortedNames1)</span><br><span class="line">testSortedNames(sortedNames1)</span><br></pre></td></tr></table></figure>
<p>现在你知道如果将来你改变排序的方式（例如：使其函数式），你可以检测到任何发生的错误。<br>从调用者到<code>sortedNamesImp(of:)</code>的角度看，他提供了一系列的<code>rieds</code>,然后输出按照名字排序的列表。<code>sortedNamesImp(of:)</code>之外的任何东西都没有改变。<br>你可以用另一个测试证明这点，将下面代码添加到<code>playground</code>底部：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> originalNames: [<span class="type">String</span>] = []</span><br><span class="line"><span class="keyword">for</span> ride <span class="keyword">in</span> parkRides &#123;</span><br><span class="line">  originalNames.append(ride.name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testOriginalNameOrder</span><span class="params">(<span class="number">_</span> names: [String])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Raging Rapids"</span>,</span><br><span class="line">                  <span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Spinning Tea Cups"</span>,</span><br><span class="line">                  <span class="string">"Spooky Hollow"</span>,</span><br><span class="line">                  <span class="string">"Thunder Coaster"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Bumper Boats"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test original name order = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(originalNames)</span><br><span class="line">testOriginalNameOrder(originalNames)</span><br></pre></td></tr></table></figure>
<p>在这个测试中，你将收集作为参数传递的游乐设施列表的名称，并根据预期的顺序测试该订单。<br>在结果区和控制台中，你将看到<code>sortedNamesImp(of:)</code>内的排序<code>rides</code>不会影响输入列表。你创建的模块化功能是半函数式的。按照名称排序<code>rides</code>是逻辑单一，可以测试的，模块化的并且可重复利的函数。<br><code>sortedNamesImp(of:)</code>中的命令式代码用于长而笨重的函数。该功能难以阅读，你无法轻易知道他干了什么事情。在下一部分你将学习如何进一步简化<code>sortedNamesImp(of:)</code>等函数中的代码。</p>
<h3 id="一等和高阶函数"><a href="#一等和高阶函数" class="headerlink" title="一等和高阶函数"></a>一等和高阶函数</h3><p>在FP语言中，函数式一等公民。你可以把函数当成对象那样那样进行赋值。<br>因此，函数可以接收其他函数作为参数或者返回值。接受或者返回其他函数的函数成为高阶函数。<br>在本节中，你将使用FP语言中的三种常见的高阶函数：<code>filter</code>,<code>map</code>,<code>reduce</code>.</p>
<h4 id="Filter"><a href="#Filter" class="headerlink" title="Filter"></a>Filter</h4><p>在swift中，<code>filter</code>是<code>Collection</code>类型的方法，例如Swift数组。它接受另一个函数作为参数。此另一个函数接受来自数组的单个值作为输入，检查该值是否属于并返回<code>Bool</code>.<br><code>filter</code>将输入函数应用于调用数组的每个元素并返回另一个数组。输出函数仅包含参数函数返回true的数组元素。<br>试试下面的例子：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> apples = [<span class="string">"🍎"</span>, <span class="string">"🍏"</span>, <span class="string">"🍎"</span>, <span class="string">"🍏"</span>, <span class="string">"🍏"</span>]</span><br><span class="line"><span class="keyword">let</span> greenapples = apples.<span class="built_in">filter</span> &#123; $<span class="number">0</span> == <span class="string">"🍏"</span>&#125;</span><br><span class="line"><span class="built_in">print</span>(greenapples)</span><br></pre></td></tr></table></figure>
<p>在输入数组中有三个青苹果，你将看到输出数组中含有三个青苹果。<br>回想一下你用<code>sortedNamesImp(of:)</code>干了什么事情。</p>
<ol>
<li>遍历所有的<code>rides</code>传递给函数的。</li>
<li>通过名字排序<code>rides</code></li>
<li>获取已排序的<code>riedes</code>的名字</li>
</ol>
<p>不要过分的考虑这一点，而是以声明的方式思考它，即考虑你想要发生什么而不是如何发生。首先创建一个函数，该函数将<code>Ride</code>对象作为函数的输入参数：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">waitTimeIsShort</span><span class="params">(<span class="number">_</span> ride: Ride)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> ride.waitTime &lt; <span class="number">15.0</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>这个函数<code>waitTimeIsShort(_:)</code>接收一个<code>Ride</code>，如果<code>ride</code>的等待时间小于15min返回true，否则返回false。<br><code>parkRides</code>调用<code>filter</code>并且传入刚刚创建的函数。</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> shortWaitTimeRides = parkRides.<span class="built_in">filter</span>(waitTimeIsShort)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"rides with a short wait time:\n\(shortWaitTimeRides)"</span>)</span><br></pre></td></tr></table></figure>
<p>在<code>playground</code>输出中，你只能在调用<code>filter(_:)</code>的输出中看到<code>Crazy Funhouse</code>和<code>Mountain Railroad</code>,这是正确的。<br>由于swift函数也被叫闭包，因此可以通过将尾随闭包传递给过滤器并且使用闭包语法来生成相同的结果：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> shortWaitTimeRides2 = parkRides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.waitTime &lt; <span class="number">15.0</span> &#125;</span><br><span class="line"><span class="built_in">print</span>(shortWaitTimeRides2)</span><br></pre></td></tr></table></figure>
<p>这里，<code>filter(_:)</code>让<code>$0</code>代表了<code>parkRides</code>中的每个<code>ride</code>，查看他的<code>waitTime</code>属性并且测试它小于15min.你声明性的告诉程序你希望做什么。在你使用的前几次你会觉得这样很神秘。</p>
<h4 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h4><p>集合方法<code>map（_:）</code>接受单个函数作为参数。在将该函数应用于集合的每个元素之后，它输出一个相同长度的数组。映射函数的返回类型不必与集合元素的类型相同。</p>
<p>试试这个：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> oranges = apples.<span class="built_in">map</span> &#123; <span class="number">_</span> <span class="keyword">in</span> <span class="string">"🍊"</span> &#125;</span><br><span class="line"><span class="built_in">print</span>(oranges)</span><br></pre></td></tr></table></figure>
<p>你把每一个苹果都映射成一个橘子，制作一个橘子盛宴。<br>您可以将<code>map（_:）</code>应用于<code>parkrides</code>数组的元素，以获取所有<code>ride</code>名称的字符串列表：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> rideNames = parkRides.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;</span><br><span class="line"><span class="built_in">print</span>(rideNames)</span><br><span class="line">testOriginalNameOrder(rideNames)</span><br></pre></td></tr></table></figure>
<p>您已经证明了使用<code>map（_:）</code>获取<code>ride</code>名称与在集合使用迭代操作相同，就像您之前所做的那样。<br>当你使用集合类型上<code>sorted（by:）</code>方法执行排序时，也可以按如下方式排序<code>ride</code>的名称：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">print</span>(rideNames.sorted(by: &lt;))</span><br></pre></td></tr></table></figure>
<p>集合方法<code>sorted（by:）</code>接受一个比较两个元素并返回bool作为参数的函数。因为运算符<code>&lt;</code>是一个牛逼的函数，所以可以使用swift缩写的尾随闭包{$0&lt;$1}。swift默认提供左侧和右侧。</p>
<p>现在，您可以将提取和排序<code>ride</code>名称的代码减少到只有两行，这要感谢<code>map（:）</code>和<code>sorted（by:）</code>。<br>使用以下代码将<code>sortedNamesImp(_:)</code>重新实现为<code>sortedNamesFP(_:)</code>：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sortedNamesFP</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> -&gt; [<span class="type">String</span>] &#123;</span><br><span class="line">  <span class="keyword">let</span> rideNames = parkRides.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;</span><br><span class="line">  <span class="keyword">return</span> rideNames.sorted(by: &lt;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedNames2 = sortedNamesFP(parkRides)</span><br><span class="line">testSortedNames(sortedNames2)</span><br></pre></td></tr></table></figure>
<p>你的声明性代码更容易阅读，你可以轻松地理解它是如何工作的。测试证明<code>sortedNamesFP(_:)</code>和<code>sortedNamesImp(_:).</code>做了相同的事情。</p>
<h4 id="Reduce"><a href="#Reduce" class="headerlink" title="Reduce"></a>Reduce</h4><p>集合方法<code>reduce（::）</code>接受两个参数：第一个是任意类型T的起始值，第二个是一个函数，该函数将同一T类型的值与集合中的元素组合在一起，以生成另一个T类型的值。<br>输入函数一个接一个地应用于调用集合的每个元素，直到它到达集合的末尾并生成最终的累积值。<br>例如，您可以将这些桔子还原为一些果汁：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> juice = oranges.<span class="built_in">reduce</span>(<span class="string">""</span>) &#123; juice, orange <span class="keyword">in</span> juice + <span class="string">"🍹"</span>&#125;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"fresh 🍊 juice is served – \(juice)"</span>)</span><br></pre></td></tr></table></figure>
<p>从空字符串开始。然后为每个桔子的字符串添加<code>🍹</code>。这段代码可以为任何数组注入果汁，因此请小心放入它：]。<br>为了更实际，添加以下方法，让您知道公园中所有游乐设施的总等待时间。</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> totalWaitTime = parkRides.<span class="built_in">reduce</span>(<span class="number">0.0</span>) &#123; (total, ride) <span class="keyword">in</span> </span><br><span class="line">  total + ride.waitTime </span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"total wait time for all rides = \(totalWaitTime) minutes"</span>)</span><br></pre></td></tr></table></figure>
<p>此函数的工作方式是将起始值0.0传递到<code>reduce</code>中，并使用尾随闭包语法来添加每次骑行占用的总等待时间。代码再次使用swift简写来省略return关键字。默认情况下，返回<code>total+ride.waittime</code>的结果。<br>在本例中，迭代如下：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">Iteration</span>    initial    ride.waitTime    resulting total</span><br><span class="line">    <span class="number">1</span>          <span class="number">0</span>            <span class="number">45</span>            <span class="number">0</span> + <span class="number">45</span> = <span class="number">45</span></span><br><span class="line">    <span class="number">2</span>         <span class="number">45</span>            <span class="number">10</span>            <span class="number">45</span> + <span class="number">10</span> = <span class="number">55</span></span><br><span class="line">    …</span><br><span class="line">    <span class="number">8</span>        <span class="number">200</span>             <span class="number">0</span>            <span class="number">200</span> + <span class="number">0</span> = <span class="number">200</span></span><br></pre></td></tr></table></figure>
<p>如您所见，得到的总数将作为下一次迭代的初始值。这将一直持续，直到<code>reduce</code>迭代了<code>parkRides</code>中的每个<code>Ride</code>。这允许你用一行代码得到总数！</p>
<h3 id="先进技术"><a href="#先进技术" class="headerlink" title="先进技术"></a>先进技术</h3><p>您已经了解了一些常见的FP方法。现在是时候用更多的函数理论来做进一步的研究了。</p>
<h4 id="Partial-Functions（局部函数）"><a href="#Partial-Functions（局部函数）" class="headerlink" title="Partial Functions（局部函数）"></a>Partial Functions（局部函数）</h4><p>部分函数允许您将一个函数封装到另一个函数中。要了解其工作原理，请将以下方法添加到playground：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">filter</span><span class="params">(<span class="keyword">for</span> category: RideCategory)</span></span> -&gt; ([<span class="type">Ride</span>]) -&gt; [<span class="type">Ride</span>] &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123; rides <span class="keyword">in</span></span><br><span class="line">    rides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.categories.<span class="built_in">contains</span>(category) &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>这里，<code>filter（for:）</code>接受一个<code>ridecategory</code>作为其参数，并返回一个类型为<code>（[Ride]）-&gt;[Ride]</code>的函数。输出函数接受一个<code>Ride</code>对象数组，并返回一个由提供的<code>category</code>过滤的<code>Ride</code>对象数组。</p>
<p>在这里通过寻找适合小孩子的游乐设施来检查过滤器：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> kidRideFilter = <span class="built_in">filter</span>(<span class="keyword">for</span>: .kids)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"some good rides for kids are:\n\(kidRideFilter(parkRides))"</span>)</span><br></pre></td></tr></table></figure>
<p>您应该可以在控制台输出中看到<code>Spinning Tea Cups</code>和<code>Grand Carousel</code>。</p>
<h4 id="纯函数"><a href="#纯函数" class="headerlink" title="纯函数"></a>纯函数</h4><p>FP中的一个主要概念是纯函数，它允许您对程序结构以及测试程序结果进行推理。<br>如果函数满足两个条件，则它是纯函数：</p>
<ul>
<li>当给定相同的输入时，函数总是产生相同的输出，例如，输出仅取决于其输入。</li>
<li>函数在其外部没有副作用。</li>
</ul>
<p>在playground中添加以下纯函数：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">ridesWithWaitTimeUnder</span><span class="params">(<span class="number">_</span> waitTime: Minutes, </span></span></span><br><span class="line"><span class="function"><span class="params">    from rides: [Ride])</span></span> -&gt; [<span class="type">Ride</span>] &#123;</span><br><span class="line">  <span class="keyword">return</span> rides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.waitTime &lt; waitTime &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><code>rides withwaittimeunder（_:from:）</code>是一个纯函数，因为当给定相同的等待时间和相同的<code>rides</code>列表时，它的输出总是相同的。</p>
<p>有了纯函数，就很容易针对该函数编写一个好的单元测试。将以下测试添加到您的playgroud：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> shortWaitRides = ridesWithWaitTimeUnder(<span class="number">15</span>, from: parkRides)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testShortWaitRides</span><span class="params">(<span class="number">_</span> testFilter:<span class="params">(Minutes, [Ride])</span></span></span> -&gt; [<span class="type">Ride</span>]) &#123;</span><br><span class="line">  <span class="keyword">let</span> limit = <span class="type">Minutes</span>(<span class="number">15</span>)</span><br><span class="line">  <span class="keyword">let</span> result = testFilter(limit, parkRides)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"rides with wait less than 15 minutes:\n\(result)"</span>)</span><br><span class="line">  <span class="keyword">let</span> names = result.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;.sorted(by: &lt;)</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test rides with wait time under 15 = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">testShortWaitRides(ridesWithWaitTimeUnder(<span class="number">_</span>:from:))</span><br></pre></td></tr></table></figure>
<p>请注意你是如何将<code>ridesWithWaitTimeUnder(_:from:)</code>传递给测试。请记住，函数是一等公民，您可以像传递任何其他数据一样传递它们。这将在下一节派上用场。<br>另外，运行你的测试程序再次使用<code>map（_:）</code>和<code>sorted（_by:）</code>提取名称。你在用FP测试你的FP技能。</p>
<h3 id="参照透明度"><a href="#参照透明度" class="headerlink" title="参照透明度"></a>参照透明度</h3><p>纯函数与参照透明的概念有关。如果一个程序的元素可以用它的定义替换它，并且总是产生相同的结果，那么它的引用是透明的。它生成可预测的代码，并允许编译器执行优化。纯函数满足这个条件。</p>
<p>通过将函数体传递给<code>ridesWithWaitTimeUnder(_:from:)</code>，可以验证函数<code>testShortWaitRides(_:)</code>是否具有引用透明性：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">testShortWaitRides(&#123; waitTime, rides <span class="keyword">in</span></span><br><span class="line">    <span class="keyword">return</span> rides.<span class="built_in">filter</span>&#123; $<span class="number">0</span>.waitTime &lt; waitTime &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<p>在这段代码中，你获取了<code>ridesWithWaitTimeUnder(_:from:)</code>，并将其直接传递给封装在闭包语法中的<code>testShortWaitrides（:）</code>。这证明了<code>ridesWithWaitTimeUnder(_:from:)</code>是引用透明的。</p>
<p>在重构某些代码时,希望确保不会破坏任何东西，引用透明性是很有用。引用透明代码不仅易于测试，而且还允许您在不必验证实现的情况下移动代码。</p>
<h3 id="递归"><a href="#递归" class="headerlink" title="递归"></a>递归</h3><p>最后要讨论的概念是递归。每当函数调用自身作为其函数体的一部分时，都会发生递归。在函数式语言中，递归替换了许多在命令式语言中使用的循环结构。</p>
<p>当函数的输入导致函数调用自身时，就有了递归情况。为了避免函数调用的无限堆栈，递归函数需要一个基本情况来结束它们。</p>
<p>您将为您的<code>rides</code>添加一个递归排序函数。首先，使用下面的拓展让<code>Ride</code>遵循<code>Comparable</code>协议：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Ride</span>: <span class="title">Comparable</span> </span>&#123;</span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> &lt;(lhs: Ride, rhs: Ride) -&gt; <span class="title">Bool</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> lhs.waitTime &lt; rhs.waitTime</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  <span class="keyword">public</span> <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> ==<span class="params">(lhs: Ride, rhs: Ride)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> lhs.name == rhs.name</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在这个扩展中，可以使用运算符重载来创建允许比较两个<code>rides</code>的函数。您还可以看到在排序之前使用的&lt;运算符的完整函数声明<code>sorted(by:)</code>。<br>如果等待时间更少，那么一个<code>ride</code>就少于另一个<code>ride</code>，如果<code>rides</code>具有相同的名称，则<code>rides</code>是相等的。<br>现在，扩展数组以包含<code>quickSorted</code>方法：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Array</span> <span class="title">where</span> <span class="title">Element</span>: <span class="title">Comparable</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">func</span> <span class="title">quickSorted</span><span class="params">()</span></span> -&gt; [<span class="type">Element</span>] &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">self</span>.<span class="built_in">count</span> &gt; <span class="number">1</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> (pivot, remaining) = (<span class="keyword">self</span>[<span class="number">0</span>], <span class="built_in">dropFirst</span>())</span><br><span class="line">      <span class="keyword">let</span> lhs = remaining.<span class="built_in">filter</span> &#123; $<span class="number">0</span> &lt;= pivot &#125;</span><br><span class="line">      <span class="keyword">let</span> rhs = remaining.<span class="built_in">filter</span> &#123; $<span class="number">0</span> &gt; pivot &#125;</span><br><span class="line">      <span class="keyword">return</span> lhs.quickSorted() + [pivot] + rhs.quickSorted()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>此扩展允许您对数组进行排序，只要元素是可比较的。<br>快速排序算法首先选择一个基准元素。然后将集合分成两部分。一部分包含小于或等于基准元素的所有元素，另一部分包含大于基准元素的其余元素。然后使用递归对这两部分进行排序。注意，通过使用递归，您不需要使用可变状态。</p>
<p>输入以下代码以验证您的方法是否正常工作：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> quickSortedRides = parkRides.quickSorted()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"\(quickSortedRides)"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedByWaitRides</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = rides.sorted(by:  &#123; $<span class="number">0</span>.waitTime &lt; $<span class="number">1</span>.waitTime &#125;)</span><br><span class="line">  <span class="built_in">assert</span>(rides == expected, <span class="string">"unexpected order"</span>)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test sorted by wait time = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">testSortedByWaitRides(quickSortedRides)</span><br></pre></td></tr></table></figure>
<p>在这里，您将检查您的解决方案是否与来自受信任的swift标准库函数的预期值匹配。<br>请记住递归函数具有额外的内存使用和运行时开销。在数据集变得更大之前，您不必担心这些问题。</p>
<h3 id="命令与声明性代码风格"><a href="#命令与声明性代码风格" class="headerlink" title="命令与声明性代码风格"></a>命令与声明性代码风格</h3><p>在本节中，您将结合您所学到的关于FP的知识来清楚地演示函数编程的好处。<br>考虑以下情况：<br>一个有小孩的家庭希望在频繁的浴室休息之间尽可能多地乘车。他们需要找出哪一种适合儿童乘车的路线最短。帮助他们找出所有家庭乘坐等待时间少于20分钟，并排序他们最短到最长的等待时间。</p>
<h4 id="用命令式方法解决问题"><a href="#用命令式方法解决问题" class="headerlink" title="用命令式方法解决问题"></a>用命令式方法解决问题</h4><p>考虑一下如何用强制算法来解决这个问题。试着用你自己的方法解决这个问题。<br>您的解决方案可能类似于：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> ridesOfInterest: [<span class="type">Ride</span>] = []</span><br><span class="line"><span class="keyword">for</span> ride <span class="keyword">in</span> parkRides <span class="keyword">where</span> ride.waitTime &lt; <span class="number">20</span> &#123;</span><br><span class="line">  <span class="keyword">for</span> category <span class="keyword">in</span> ride.categories <span class="keyword">where</span> category == .family &#123;</span><br><span class="line">    ridesOfInterest.append(ride)</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedRidesOfInterest1 = ridesOfInterest.quickSorted()</span><br><span class="line"><span class="built_in">print</span>(sortedRidesOfInterest1)</span><br></pre></td></tr></table></figure>
<p>把这个加到你的<code>playground</code>上并执行它。你应该看到，<code>Mountain Railroad</code>, <code>Crazy Funhouse</code> 和<code>Grand Carousel</code> 是最好的乘坐选择，该名单是为了增加等待时间。</p>
<p>正如所写的，命令式代码很好，但快速浏览并不能清楚地显示它正在做什么。你必须停下来仔细看看算法来掌握它。当您六个月后返回进行维护时，或者将代码交给新的开发人员时，代码是否容易理解？</p>
<p>添加此测试以将FP方法与您的命令式解决方案进行比较：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedRidesOfInterest</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> names = rides.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;.sorted(by: &lt;)</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test rides of interest = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">testSortedRidesOfInterest(sortedRidesOfInterest1)</span><br></pre></td></tr></table></figure>

<h4 id="用函数方法解决问题"><a href="#用函数方法解决问题" class="headerlink" title="用函数方法解决问题"></a>用函数方法解决问题</h4><p>使用FP解决方案，您可以使代码更具自解释性。将以下代码添加到您的playground：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> sortedRidesOfInterest2 = parkRides</span><br><span class="line">    .<span class="built_in">filter</span> &#123; $<span class="number">0</span>.categories.<span class="built_in">contains</span>(.family) &amp;&amp; $<span class="number">0</span>.waitTime &lt; <span class="number">20</span> &#125;</span><br><span class="line">    .sorted(by: &lt;)</span><br></pre></td></tr></table></figure>
<p>通过添加以下内容，验证这行代码是否生成与命令代码相同的输出：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">testSortedRidesOfInterest(sortedRidesOfInterest2)</span><br></pre></td></tr></table></figure>
<p>在一行代码中，您告诉swift要计算什么。您希望将您的<code>parkRides</code>过滤到具有小于20分钟的等待时间的<code>.family</code>的游乐设施，然后对它们排序。这就彻底解决了上述问题。<br>生成的代码是声明性的，这意味着它是自解释的，并且读起来就像它解决的问题陈述。<br>这与命令式代码不同，命令式代码读起来像是计算机解决问题语句所必须采取的步骤。</p>
<h3 id="函数编程的时间和原因"><a href="#函数编程的时间和原因" class="headerlink" title="函数编程的时间和原因"></a>函数编程的时间和原因</h3><p>Swift不是纯粹的函数式编程语言，但它结合了多种编程范式，为您提供了应用程序开发的灵活性。<br>开始使用FP技术的一个好地方是在模型层和应用程序的业务逻辑出现的地方。您已经看到创建这种逻辑的离散测试是多么容易。<br>对于用户界面，不太清楚看哪里可以使用FP编程。<code>Reactive programming</code>是一种用于用户界面开发的类似于FP的方法的例子。例如，RxSwift是一个用于IOS和MACOS编程的反应库。<br>通过使用函数式，声明性方法，代码变得更加简洁明了。另外，当代码被隔离到没有副作用的模块化函数中时，它将更容易测试。<br>当你想最大化你的多核CPU的全部潜力时，最小化并发带来的副作用和问题是很重要的。FP是一个很好的工具，在你的技能中应对那些问题。</p>
<p>本文涉及的全部代码：</p>
<figure class="highlight swift"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br><span class="line">322</span><br><span class="line">323</span><br><span class="line">324</span><br><span class="line">325</span><br><span class="line">326</span><br><span class="line">327</span><br><span class="line">328</span><br><span class="line">329</span><br><span class="line">330</span><br><span class="line">331</span><br><span class="line">332</span><br><span class="line">333</span><br><span class="line">334</span><br><span class="line">335</span><br><span class="line">336</span><br><span class="line">337</span><br><span class="line">338</span><br><span class="line">339</span><br><span class="line">340</span><br><span class="line">341</span><br><span class="line">342</span><br><span class="line">343</span><br><span class="line">344</span><br><span class="line">345</span><br><span class="line">346</span><br><span class="line">347</span><br><span class="line">348</span><br><span class="line">349</span><br><span class="line">350</span><br><span class="line">351</span><br><span class="line">352</span><br><span class="line">353</span><br><span class="line">354</span><br><span class="line">355</span><br><span class="line">356</span><br><span class="line">357</span><br><span class="line">358</span><br><span class="line">359</span><br><span class="line">360</span><br><span class="line">361</span><br><span class="line">362</span><br><span class="line">363</span><br><span class="line">364</span><br><span class="line">365</span><br><span class="line">366</span><br><span class="line">367</span><br><span class="line">368</span><br><span class="line">369</span><br><span class="line">370</span><br><span class="line">371</span><br><span class="line">372</span><br><span class="line">373</span><br><span class="line">374</span><br><span class="line">375</span><br><span class="line">376</span><br><span class="line">377</span><br><span class="line">378</span><br><span class="line">379</span><br><span class="line">380</span><br><span class="line">381</span><br><span class="line">382</span><br><span class="line">383</span><br><span class="line">384</span><br><span class="line">385</span><br><span class="line">386</span><br><span class="line">387</span><br><span class="line">388</span><br><span class="line">389</span><br><span class="line">390</span><br><span class="line">391</span><br><span class="line">392</span><br><span class="line">393</span><br><span class="line">394</span><br><span class="line">395</span><br><span class="line">396</span><br><span class="line">397</span><br><span class="line">398</span><br><span class="line">399</span><br><span class="line">400</span><br><span class="line">401</span><br><span class="line">402</span><br><span class="line">403</span><br><span class="line">404</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/// Copyright (c) 2018 Razeware LLC</span></span><br><span class="line"><span class="comment">///</span></span><br><span class="line"><span class="comment">/// Permission is hereby granted, free of charge, to any person obtaining a copy</span></span><br><span class="line"><span class="comment">/// of this software and associated documentation files (the "Software"), to deal</span></span><br><span class="line"><span class="comment">/// in the Software without restriction, including without limitation the rights</span></span><br><span class="line"><span class="comment">/// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</span></span><br><span class="line"><span class="comment">/// copies of the Software, and to permit persons to whom the Software is</span></span><br><span class="line"><span class="comment">/// furnished to do so, subject to the following conditions:</span></span><br><span class="line"><span class="comment">///</span></span><br><span class="line"><span class="comment">/// The above copyright notice and this permission notice shall be included in</span></span><br><span class="line"><span class="comment">/// all copies or substantial portions of the Software.</span></span><br><span class="line"><span class="comment">///</span></span><br><span class="line"><span class="comment">/// Notwithstanding the foregoing, you may not use, copy, modify, merge, publish,</span></span><br><span class="line"><span class="comment">/// distribute, sublicense, create a derivative work, and/or sell copies of the</span></span><br><span class="line"><span class="comment">/// Software in any work that is designed, intended, or marketed for pedagogical or</span></span><br><span class="line"><span class="comment">/// instructional purposes related to programming, coding, application development,</span></span><br><span class="line"><span class="comment">/// or information technology.  Permission for such use, copying, modification,</span></span><br><span class="line"><span class="comment">/// merger, publication, distribution, sublicensing, creation of derivative works,</span></span><br><span class="line"><span class="comment">/// or sale is expressly withheld.</span></span><br><span class="line"><span class="comment">///</span></span><br><span class="line"><span class="comment">/// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</span></span><br><span class="line"><span class="comment">/// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</span></span><br><span class="line"><span class="comment">/// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</span></span><br><span class="line"><span class="comment">/// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</span></span><br><span class="line"><span class="comment">/// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</span></span><br><span class="line"><span class="comment">/// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN</span></span><br><span class="line"><span class="comment">/// THE SOFTWARE.</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">import</span> Foundation</span><br><span class="line"></span><br><span class="line"><span class="comment">//: # Introduction to Functional Programming</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Imperative Style</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Command your data!</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> thing = <span class="number">3</span></span><br><span class="line"><span class="comment">//some stuff</span></span><br><span class="line">thing = <span class="number">4</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Side effects</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Holy mysterious change! - Why is my thing now 5?</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">superHero</span><span class="params">()</span></span> &#123;</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"I'm batman"</span>)</span><br><span class="line">  thing = <span class="number">5</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(<span class="string">"original state = \(thing)"</span>)</span><br><span class="line">superHero()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"mutated state = \(thing)"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Create a Model</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">enum</span> <span class="title">RideCategory</span>: <span class="title">String</span> </span>&#123;</span><br><span class="line">  <span class="keyword">case</span> family</span><br><span class="line">  <span class="keyword">case</span> kids</span><br><span class="line">  <span class="keyword">case</span> thrill</span><br><span class="line">  <span class="keyword">case</span> scary</span><br><span class="line">  <span class="keyword">case</span> relaxing</span><br><span class="line">  <span class="keyword">case</span> water</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">typealias</span> <span class="type">Minutes</span> = <span class="type">Double</span></span><br><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">Ride</span> </span>&#123;</span><br><span class="line">  <span class="keyword">let</span> name: <span class="type">String</span></span><br><span class="line">  <span class="keyword">let</span> categories: <span class="type">Set</span>&lt;<span class="type">RideCategory</span>&gt;</span><br><span class="line">  <span class="keyword">let</span> waitTime: <span class="type">Minutes</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Create some data using that model</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">let</span> parkRides = [</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Raging Rapids"</span>,</span><br><span class="line">       categories: [.family, .thrill, .water],</span><br><span class="line">       waitTime: <span class="number">45.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Crazy Funhouse"</span>, categories: [.family], waitTime: <span class="number">10.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Spinning Tea Cups"</span>, categories: [.kids], waitTime: <span class="number">15.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Spooky Hollow"</span>, categories: [.scary], waitTime: <span class="number">30.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Thunder Coaster"</span>,</span><br><span class="line">       categories: [.family, .thrill],</span><br><span class="line">       waitTime: <span class="number">60.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Grand Carousel"</span>, categories: [.family, .kids], waitTime: <span class="number">15.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Bumper Boats"</span>, categories: [.family, .water], waitTime: <span class="number">25.0</span>),</span><br><span class="line">  <span class="type">Ride</span>(name: <span class="string">"Mountain Railroad"</span>,</span><br><span class="line">       categories: [.family, .relaxing],</span><br><span class="line">       waitTime: <span class="number">0.0</span>)</span><br><span class="line">]</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ### Attempt to change immutable data.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//parkRides[0] = Ride(name: "Functional Programming", categories: [.thrill], waitTime: 5.0)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Modularity</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Create a function that does one thing.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> 1. Returns the names of the rides in alphabetical order.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sortedNamesImp</span><span class="params">(of rides: [Ride])</span></span> -&gt; [<span class="type">String</span>] &#123;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 1</span></span><br><span class="line">  <span class="keyword">var</span> sortedRides = rides</span><br><span class="line">  <span class="keyword">var</span> key: <span class="type">Ride</span></span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 2</span></span><br><span class="line">  <span class="keyword">for</span> i <span class="keyword">in</span> (<span class="number">0</span>..&lt;sortedRides.<span class="built_in">count</span>) &#123;</span><br><span class="line">    key = sortedRides[i]</span><br><span class="line">    </span><br><span class="line">    <span class="comment">// 3</span></span><br><span class="line">    <span class="keyword">for</span> j <span class="keyword">in</span> <span class="built_in">stride</span>(from: i, to: -<span class="number">1</span>, by: -<span class="number">1</span>) &#123;</span><br><span class="line">      <span class="keyword">if</span> key.name.localizedCompare(sortedRides[j].name) == .orderedAscending &#123;</span><br><span class="line">        sortedRides.remove(at: j + <span class="number">1</span>)</span><br><span class="line">        sortedRides.insert(key, at: j)</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="comment">// 4</span></span><br><span class="line">  <span class="keyword">var</span> sortedNames: [<span class="type">String</span>] = []</span><br><span class="line">  <span class="keyword">for</span> ride <span class="keyword">in</span> sortedRides &#123;</span><br><span class="line">    sortedNames.append(ride.name)</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">return</span> sortedNames</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedNames1 = sortedNamesImp(of: parkRides)</span><br><span class="line"></span><br><span class="line"><span class="comment">//: Test your new function</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedNames</span><span class="params">(<span class="number">_</span> names: [String])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Bumper Boats"</span>,</span><br><span class="line">                  <span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>,</span><br><span class="line">                  <span class="string">"Raging Rapids"</span>,</span><br><span class="line">                  <span class="string">"Spinning Tea Cups"</span>,</span><br><span class="line">                  <span class="string">"Spooky Hollow"</span>,</span><br><span class="line">                  <span class="string">"Thunder Coaster"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test sorted names = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(sortedNames1)</span><br><span class="line">testSortedNames(sortedNames1)</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> originalNames: [<span class="type">String</span>] = []</span><br><span class="line"><span class="keyword">for</span> ride <span class="keyword">in</span> parkRides &#123;</span><br><span class="line">  originalNames.append(ride.name)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//: Test that original data is untouched</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testOriginalNameOrder</span><span class="params">(<span class="number">_</span> names: [String])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Raging Rapids"</span>,</span><br><span class="line">                  <span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Spinning Tea Cups"</span>,</span><br><span class="line">                  <span class="string">"Spooky Hollow"</span>,</span><br><span class="line">                  <span class="string">"Thunder Coaster"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Bumper Boats"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test original name order = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(originalNames)</span><br><span class="line">testOriginalNameOrder(originalNames)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## First class and higher order functions.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Most languages that support FP will have the functions `filter`, `map` &amp; `reduce`.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> ### Filter</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Filter takes the input `Collection` and filters it according to the function you provide.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Here's a simple example.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> apples = [<span class="string">"🍎"</span>, <span class="string">"🍏"</span>, <span class="string">"🍎"</span>, <span class="string">"🍏"</span>, <span class="string">"🍏"</span>]</span><br><span class="line"><span class="keyword">let</span> greenapples = apples.<span class="built_in">filter</span> &#123; $<span class="number">0</span> == <span class="string">"🍏"</span>&#125;</span><br><span class="line"><span class="built_in">print</span>(greenapples)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//: Next, try filtering your ride data</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">waitTimeIsShort</span><span class="params">(<span class="number">_</span> ride: Ride)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">  <span class="keyword">return</span> ride.waitTime &lt; <span class="number">15.0</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> shortWaitTimeRides = parkRides.<span class="built_in">filter</span>(waitTimeIsShort)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"rides with a short wait time:\n\(shortWaitTimeRides)"</span>)</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> shortWaitTimeRides2 = parkRides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.waitTime &lt; <span class="number">15.0</span> &#125;</span><br><span class="line"><span class="built_in">print</span>(shortWaitTimeRides2)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ### Minor detour: CustomStringConvertible</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> You want to make your console output look nice.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">RideCategory</span>: <span class="title">CustomStringConvertible</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> description: <span class="type">String</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> rawValue</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Ride</span>: <span class="title">CustomStringConvertible</span> </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> description: <span class="type">String</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="string">"Ride –\"\(name)\", wait: \(waitTime) mins, categories: \(categories)\n"</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ### Map</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Map converts each `Element` in the input `Collection` into a new thing based on the function that you provide.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> First create oranges from apples.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">let</span> oranges = apples.<span class="built_in">map</span> &#123; <span class="number">_</span> <span class="keyword">in</span> <span class="string">"🍊"</span> &#125;</span><br><span class="line"><span class="built_in">print</span>(oranges)</span><br><span class="line"></span><br><span class="line"><span class="comment">//: Now extract the names of your rides</span></span><br><span class="line"><span class="keyword">let</span> rideNames = parkRides.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;</span><br><span class="line"><span class="built_in">print</span>(rideNames)</span><br><span class="line">testOriginalNameOrder(rideNames)</span><br><span class="line"></span><br><span class="line"><span class="built_in">print</span>(rideNames.sorted(by: &lt;))</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">sortedNamesFP</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> -&gt; [<span class="type">String</span>] &#123;</span><br><span class="line">  <span class="keyword">let</span> rideNames = parkRides.<span class="built_in">map</span> &#123; $<span class="number">0</span>.name &#125;</span><br><span class="line">  <span class="keyword">return</span> rideNames.sorted(by: &lt;)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedNames2 = sortedNamesFP(parkRides)</span><br><span class="line">testSortedNames(sortedNames2)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ### Reduce</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Reduce iterates across the input `Collection` to reduce it to a single value.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> You can squish your oranges into one juicy string.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">let</span> juice = oranges.<span class="built_in">reduce</span>(<span class="string">""</span>)&#123;juice, orange <span class="keyword">in</span> juice + <span class="string">"🍹"</span>&#125;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"fresh 🍊 juice is served – \(juice)"</span>)</span><br><span class="line"></span><br><span class="line"><span class="comment">//: Here you **reduce** the collection to a single value of type `Minutes` (a.k.a `Double`)</span></span><br><span class="line"><span class="keyword">let</span> totalWaitTime = parkRides.<span class="built_in">reduce</span>(<span class="number">0.0</span>) &#123; (total, ride) <span class="keyword">in</span></span><br><span class="line">  total + ride.waitTime</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"total wait time for all rides = \(totalWaitTime) minutes"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Partial Functions</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> A function can return a function.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> `filter(for:)` returns a function of type `([Ride]) -&gt; ([Ride])`</span></span><br><span class="line"><span class="comment"> it takes and returns an array of `Ride` objects</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">filter</span><span class="params">(<span class="keyword">for</span> category: RideCategory)</span></span> -&gt; ([<span class="type">Ride</span>]) -&gt; [<span class="type">Ride</span>] &#123;</span><br><span class="line">  <span class="keyword">return</span> &#123; (rides: [<span class="type">Ride</span>]) <span class="keyword">in</span></span><br><span class="line">    rides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.categories.<span class="built_in">contains</span>(category) &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//: you can use it to filter the list for all rides that are suitable for kids.</span></span><br><span class="line"><span class="keyword">let</span> kidRideFilter = <span class="built_in">filter</span>(<span class="keyword">for</span>: .kids)</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"some good rides for kids are:\n\(kidRideFilter(parkRides))"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Pure Functions</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> - Always give same output for same input</span></span><br><span class="line"><span class="comment"> - Have no side effects</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">ridesWithWaitTimeUnder</span><span class="params">(<span class="number">_</span> waitTime: Minutes,</span></span></span><br><span class="line"><span class="function"><span class="params">                            from rides: [Ride])</span></span> -&gt; [<span class="type">Ride</span>] &#123;</span><br><span class="line">  <span class="keyword">return</span> rides.<span class="built_in">filter</span> &#123; $<span class="number">0</span>.waitTime &lt; waitTime &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> shortWaitRides = ridesWithWaitTimeUnder(<span class="number">15</span>, from: parkRides)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testShortWaitRides</span><span class="params">(<span class="number">_</span> testFilter:<span class="params">(Minutes, [Ride])</span></span></span> -&gt; [<span class="type">Ride</span>]) &#123;</span><br><span class="line">  <span class="keyword">let</span> limit = <span class="type">Minutes</span>(<span class="number">15</span>)</span><br><span class="line">  <span class="keyword">let</span> result = testFilter(limit, parkRides)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"rides with wait less than 15 minutes:\n\(result)"</span>)</span><br><span class="line">  <span class="keyword">let</span> names = result.<span class="built_in">map</span>&#123; $<span class="number">0</span>.name &#125;.sorted(by: &lt;)</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test rides with wait time under 15 = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">testShortWaitRides(ridesWithWaitTimeUnder(<span class="number">_</span>:from:))</span><br><span class="line"></span><br><span class="line"><span class="comment">//: when you replace the function with its body, you expect the same result</span></span><br><span class="line">testShortWaitRides(&#123; waitTime, rides <span class="keyword">in</span></span><br><span class="line">  rides.<span class="built_in">filter</span>&#123; $<span class="number">0</span>.waitTime &lt; waitTime &#125;</span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Recursion</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Recursion is when a function calls itself as part of its function body.</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Make `Ride` conform to `Comparable` so you can compare two `Ride` objects:</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Ride</span>: <span class="title">Comparable</span> </span>&#123;</span><br><span class="line">  <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> &lt;(lhs: Ride, rhs: Ride) -&gt; <span class="title">Bool</span> </span>&#123;</span><br><span class="line">    <span class="keyword">return</span> lhs.waitTime &lt; rhs.waitTime</span><br><span class="line">  &#125;</span><br><span class="line">  </span><br><span class="line">  <span class="keyword">static</span> <span class="function"><span class="keyword">func</span> ==<span class="params">(lhs: Ride, rhs: Ride)</span></span> -&gt; <span class="type">Bool</span> &#123;</span><br><span class="line">    <span class="keyword">return</span> lhs.name == rhs.name</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> Next add a `quickSorted` algorithim to `Array`</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="class"><span class="keyword">extension</span> <span class="title">Array</span> <span class="title">where</span> <span class="title">Element</span>: <span class="title">Comparable</span> </span>&#123;</span><br><span class="line">  <span class="function"><span class="keyword">func</span> <span class="title">quickSorted</span><span class="params">()</span></span> -&gt; [<span class="type">Element</span>] &#123;</span><br><span class="line">    <span class="keyword">if</span> <span class="keyword">self</span>.<span class="built_in">count</span> &gt; <span class="number">1</span> &#123;</span><br><span class="line">      <span class="keyword">let</span> (pivot, remaining) = (<span class="keyword">self</span>[<span class="number">0</span>], <span class="built_in">dropFirst</span>())</span><br><span class="line">      <span class="keyword">let</span> lhs = remaining.<span class="built_in">filter</span> &#123; $<span class="number">0</span> &lt;= pivot &#125;</span><br><span class="line">      <span class="keyword">let</span> rhs = remaining.<span class="built_in">filter</span> &#123; $<span class="number">0</span> &gt; pivot &#125;</span><br><span class="line">      <span class="keyword">return</span> lhs.quickSorted() + [pivot] + rhs.quickSorted()</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">self</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//: test your algorithm</span></span><br><span class="line"><span class="keyword">let</span> quickSortedRides = parkRides.quickSorted()</span><br><span class="line"><span class="built_in">print</span>(<span class="string">"\(quickSortedRides)"</span>)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> check that your solution matches the expected value from the standard library function</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedByWaitRides</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> expected = rides.sorted(by:  &#123; $<span class="number">0</span>.waitTime &lt; $<span class="number">1</span>.waitTime &#125;)</span><br><span class="line">  <span class="built_in">assert</span>(rides == expected, <span class="string">"unexpected order"</span>)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test sorted by wait time = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">testSortedByWaitRides(quickSortedRides)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ## Imperative vs Declarative style</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> ### Imperitive style. Fill a container with the right things.</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">var</span> ridesOfInterest: [<span class="type">Ride</span>] = []</span><br><span class="line"><span class="keyword">for</span> ride <span class="keyword">in</span> parkRides <span class="keyword">where</span> ride.waitTime &lt; <span class="number">20</span> &#123;</span><br><span class="line">  <span class="keyword">for</span> category <span class="keyword">in</span> ride.categories <span class="keyword">where</span> category == .family &#123;</span><br><span class="line">    ridesOfInterest.append(ride)</span><br><span class="line">    <span class="keyword">break</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> sortedRidesOfInterest1 = ridesOfInterest.quickSorted()</span><br><span class="line"><span class="built_in">print</span>(sortedRidesOfInterest1)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">func</span> <span class="title">testSortedRidesOfInterest</span><span class="params">(<span class="number">_</span> rides: [Ride])</span></span> &#123;</span><br><span class="line">  <span class="keyword">let</span> names = rides.<span class="built_in">map</span>(&#123; $<span class="number">0</span>.name &#125;).sorted(by: &lt;)</span><br><span class="line">  <span class="keyword">let</span> expected = [<span class="string">"Crazy Funhouse"</span>,</span><br><span class="line">                  <span class="string">"Grand Carousel"</span>,</span><br><span class="line">                  <span class="string">"Mountain Railroad"</span>]</span><br><span class="line">  <span class="built_in">assert</span>(names == expected)</span><br><span class="line">  <span class="built_in">print</span>(<span class="string">"✅ test rides of interest = PASS\n-"</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">testSortedRidesOfInterest(sortedRidesOfInterest1)</span><br><span class="line"></span><br><span class="line"><span class="comment">/*:</span></span><br><span class="line"><span class="comment"> ### Functional Approach</span></span><br><span class="line"><span class="comment"> </span></span><br><span class="line"><span class="comment"> Declare what you're doing. Filter, Sort, Profit :]</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">let</span> sortedRidesOfInterest2 = parkRides</span><br><span class="line">  .<span class="built_in">filter</span> &#123; $<span class="number">0</span>.categories.<span class="built_in">contains</span>(.family) &amp;&amp; $<span class="number">0</span>.waitTime &lt; <span class="number">20</span> &#125;</span><br><span class="line">  .sorted(by: &lt;)</span><br><span class="line"></span><br><span class="line">testSortedRidesOfInterest(sortedRidesOfInterest2)</span><br></pre></td></tr></table></figure>
    </article>
    <!-- license  -->
    
        <div class="license-wrapper">
            <p>Author：<a href="http://kurumi.gitee.io/shanks">驿路星辰</a>
            <p>原文链接：<a href="http://kurumi.gitee.io/shanks/2019/10/03/how-to-use-functional-program-in-swift/">http://kurumi.gitee.io/shanks/2019/10/03/how-to-use-functional-program-in-swift/</a>
            <p>发表日期：<a href="http://kurumi.gitee.io/shanks/2019/10/03/how-to-use-functional-program-in-swift/">October 3rd 2019</a>
            <p>更新日期：<a href="http://kurumi.gitee.io/shanks/2019/10/03/how-to-use-functional-program-in-swift/">October 3rd 2019</a>
            <p>版权声明：本文采用<a rel="license noopener" href="http://creativecommons.org/licenses/by-nc/4.0/" target="_blank">知识共享署名-非商业性使用 4.0 国际许可协议</a>进行许可</p>
        </div>
    
    <!-- paginator  -->
    <ul class="post-paginator">
        <li class="next">
            
                <div class="nextSlogan">Next Post</div>
                <a href= "/shanks/2019/10/11/swift-function-program/" title= "【译】Swift和函数式编程的精髓">
                    <div class="nextTitle">【译】Swift和函数式编程的精髓</div>
                </a>
            
        </li>
        <li class="previous">
            
                <div class="prevSlogan">Previous Post</div>
                <a href= "/shanks/2019/08/28/swift-operator-override/" title= "【译】如何在swift中使用函数式编程">
                    <div class="prevTitle">【译】如何在swift中使用函数式编程</div>
                </a>
            
        </li>
    </ul>
    <!-- 评论插件 -->
    <!-- 来必力City版安装代码 -->

<!-- City版安装代码已完成 -->
    
    
    <!-- gitalk评论 -->

    <!-- utteranc评论 -->

    <!-- partial('_partial/comment/changyan') -->
    <!--PC版-->


    
    

    <!-- 评论 -->
</main>
            <!-- profile -->
            
        </div>
        <footer class="footer footer-unloaded">
    <!-- social  -->
    
    <div class="social">
        
    
        
            
                <a href="mailto:ayaseeri@126.com" class="iconfont-archer email" title=email ></a>
            
        
    
        
            
                <a href="//github.com/esdeath" class="iconfont-archer github" target="_blank" title=github></a>
            
        
    
        
    
        
    

    </div>
    
    <!-- powered by Hexo  -->
    <div class="copyright">
        <span id="hexo-power">Powered by <a href="https://hexo.io/" target="_blank">Hexo</a></span><span class="iconfont-archer power">&#xe635;</span><span id="theme-info">theme <a href="https://github.com/fi3ework/hexo-theme-archer" target="_blank">Archer</a></span>
    </div>
    <!-- 不蒜子  -->
    
    <div class="busuanzi-container">
    
     
    <span id="busuanzi_container_site_pv">PV: <span id="busuanzi_value_site_pv"></span> :)</span>
    
    </div>
    
</footer>
    </div>
    <!-- toc -->
    
    <div class="toc-wrapper" style=
    







top:50vh;

    >
        <div class="toc-catalog">
            <span class="iconfont-archer catalog-icon">&#xe613;</span><span>CATALOG</span>
        </div>
        <ol class="toc"><li class="toc-item toc-level-3"><a class="toc-link" href="#开始"><span class="toc-number">1.</span> <span class="toc-text">开始</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命令式编程风格"><span class="toc-number">2.</span> <span class="toc-text">命令式编程风格</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数式编程概念"><span class="toc-number">3.</span> <span class="toc-text">函数式编程概念</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#不变性和副作用"><span class="toc-number">4.</span> <span class="toc-text">不变性和副作用</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#创建游乐园的模型"><span class="toc-number">5.</span> <span class="toc-text">创建游乐园的模型</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#模块化"><span class="toc-number">6.</span> <span class="toc-text">模块化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#一等和高阶函数"><span class="toc-number">7.</span> <span class="toc-text">一等和高阶函数</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Filter"><span class="toc-number">7.1.</span> <span class="toc-text">Filter</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Map"><span class="toc-number">7.2.</span> <span class="toc-text">Map</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Reduce"><span class="toc-number">7.3.</span> <span class="toc-text">Reduce</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#先进技术"><span class="toc-number">8.</span> <span class="toc-text">先进技术</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Partial-Functions（局部函数）"><span class="toc-number">8.1.</span> <span class="toc-text">Partial Functions（局部函数）</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#纯函数"><span class="toc-number">8.2.</span> <span class="toc-text">纯函数</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#参照透明度"><span class="toc-number">9.</span> <span class="toc-text">参照透明度</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#递归"><span class="toc-number">10.</span> <span class="toc-text">递归</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#命令与声明性代码风格"><span class="toc-number">11.</span> <span class="toc-text">命令与声明性代码风格</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#用命令式方法解决问题"><span class="toc-number">11.1.</span> <span class="toc-text">用命令式方法解决问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#用函数方法解决问题"><span class="toc-number">11.2.</span> <span class="toc-text">用函数方法解决问题</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#函数编程的时间和原因"><span class="toc-number">12.</span> <span class="toc-text">函数编程的时间和原因</span></a></li></ol>
    </div>
    
    <div class="back-top iconfont-archer">&#xe639;</div>
    <div class="sidebar sidebar-hide">
    <ul class="sidebar-tabs sidebar-tabs-active-0">
        <li class="sidebar-tab-archives"><span class="iconfont-archer">&#xe67d;</span><span class="tab-name">Archive</span></li>
        <li class="sidebar-tab-tags"><span class="iconfont-archer">&#xe61b;</span><span class="tab-name">Tag</span></li>
        <li class="sidebar-tab-categories"><span class="iconfont-archer">&#xe666;</span><span class="tab-name">Cate</span></li>
    </ul>
    <div class="sidebar-content sidebar-content-show-archive">
          <div class="sidebar-panel-archives">
    <!-- 在ejs中将archive按照时间排序 -->
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    <div class="total-and-search">
        <div class="total-archive">
        Total : 16
        </div>
        <!-- search  -->
        
    </div>
    
    <div class="post-archive">
    
    
    
    
    <div class="archive-year"> 2020 </div>
    <ul class="year-list">
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">08/29</span><a class="archive-post-title" href= "/shanks/2020/08/29/flutter-ios-plugin-delegate-error/" >Flutter中针对iOS封装Plugin组件注意事项</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">08/29</span><a class="archive-post-title" href= "/shanks/2020/08/29/flutter-mvvm/" >Flutter中使用Provider实现MVVM架构</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">06/07</span><a class="archive-post-title" href= "/shanks/2020/06/07/crypt-night/" >9.SSL/TLS(为了更安全的通信)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/31</span><a class="archive-post-title" href= "/shanks/2020/05/31/crypt-eight/" >8.证书(为公钥加上数字签名)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/29</span><a class="archive-post-title" href= "/shanks/2020/05/29/crypt-seven/" >7.数字签名(消息到底是谁写的)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/21</span><a class="archive-post-title" href= "/shanks/2020/05/21/crypt-six/" >6.消息认证码(消息被正确传送了吗)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/12</span><a class="archive-post-title" href= "/shanks/2020/05/12/crypt-five-md/" >5.单向散列函数(获取消息的指纹)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/08</span><a class="archive-post-title" href= "/shanks/2020/05/08/crypt-four-md/" >4.非对称加密(公钥加密,私钥解密)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">05/05</span><a class="archive-post-title" href= "/shanks/2020/05/05/crypt-three-md/" >3. 分组密码的模式(分组密码是如何迭代)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">04/30</span><a class="archive-post-title" href= "/shanks/2020/04/30/crypt-two-md/" >2.对称加密（相同密钥加解密)---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">04/29</span><a class="archive-post-title" href= "/shanks/2020/04/29/crypt-one-md/" >1.密码学 ---《图解密码学》</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">03/27</span><a class="archive-post-title" href= "/shanks/2020/03/27/ios-gcd-ptread/" >iOS 90%人可能都会回答错误的一个多线程基础题</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">01/27</span><a class="archive-post-title" href= "/shanks/2020/01/27/how-to-know-highorlow-computer-md/" >如何判断机器的字节顺序是高字节在前还是低字节在前</a>
        </li>
    
    
    
    
    
        </ul>
    
    <div class="archive-year"> 2019 </div>
    <ul class="year-list">
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">10/11</span><a class="archive-post-title" href= "/shanks/2019/10/11/swift-function-program/" >【译】Swift和函数式编程的精髓</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">10/03</span><a class="archive-post-title" href= "/shanks/2019/10/03/how-to-use-functional-program-in-swift/" >【译】如何在swift中使用函数式编程</a>
        </li>
    
    
        <li class="archive-post-item">
            <span class="archive-post-date">08/28</span><a class="archive-post-title" href= "/shanks/2019/08/28/swift-operator-override/" >【译】如何在swift中使用函数式编程</a>
        </li>
    
    </div>
  </div>
        <div class="sidebar-panel-tags">
    <div class="sidebar-tags-name">
    
    </div>
    <div class="iconfont-archer sidebar-tags-empty">&#xe678;</div>
    <div class="tag-load-fail" style="display: none; color: #ccc; font-size: 0.6rem;">
    缺失模块。<br/>
    1、请确保node版本大于6.2<br/>
    2、在博客根目录（注意不是archer根目录）执行以下命令：<br/>
    <span style="color: #f75357; font-size: 1rem; line-height: 2rem;">npm i hexo-generator-json-content --save</span><br/>
    3、在根目录_config.yml里添加配置：
    <pre style="color: #787878; font-size: 0.6rem;">
jsonContent:
  meta: false
  pages: false
  posts:
    title: true
    date: true
    path: true
    text: false
    raw: false
    content: false
    slug: false
    updated: false
    comments: false
    link: false
    permalink: false
    excerpt: false
    categories: true
    tags: true</pre>
    </div> 
    <div class="sidebar-tags-list"></div>
</div>
        <div class="sidebar-panel-categories">
    <div class="sidebar-categories-name">
    
    </div>
    <div class="iconfont-archer sidebar-categories-empty">&#xe678;</div>
    <div class="sidebar-categories-list"></div>
</div>
    </div>
</div> 
    <script>
    var siteMeta = {
        root: "/shanks/",
        author: "驿路星辰"
    }
</script>
    <!-- CDN failover -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script>
    <script type="text/javascript">
        if (typeof window.$ === 'undefined')
        {
            console.warn('jquery load from jsdelivr failed, will load local script')
            document.write('<script src="/shanks/lib/jquery.min.js">\x3C/script>')
        }
    </script>
    <script src="/shanks/scripts/main.js"></script>
    <!-- algolia -->
    
    <!-- busuanzi  -->
    
    <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    
    <!-- CNZZ  -->
    
    </div>
    <!-- async load share.js -->
    
        <script src="/shanks/scripts/share.js" async></script>    
     
    </body>
</html>


